home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / Origami / Sources / src / origami / prompts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  34.5 KB  |  1,323 lines

  1. /*{{{}}}*/
  2. /*{{{  #includes*/
  3. #ifdef CONFIG_H
  4. #   include "config.h"
  5. #endif
  6.  
  7. #include <sys/types.h>
  8. #include <ctype.h>
  9. #include <limits.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15.  
  16. #define PROMPT_C
  17. #define I_LOOP_C
  18. #define I_DISPLAY_C
  19. #define I_GETMSG_C
  20. #define I_GETTK_C
  21. #define I_FIELDEDIT_C
  22. #define I_FILEC_C
  23. #define I_FOLDHELP_C
  24. #define I_INIT_C
  25. #define I_KEYBOARD_C
  26. #define I_KEYTAB_C
  27. #define I_MAIN_C
  28. #define I_MESSAGES_C
  29. #define I_MISC_C
  30. #define I_ORIEDT_C
  31. #define I_SCREEN_C
  32. #define I_STRING_C
  33. #define I_SET_C
  34. #define I_VIRTUAL_C
  35.  
  36. #include "origami.h"
  37. #include <lib/ori_add_lib.h>
  38. #include <lib/ori_rc_lib.h>
  39. #include <h/rcformat.h>
  40. #include <h/envvar_str.h>
  41. /*}}}  */
  42.  
  43. /*{{{  variables*/
  44. private boolean status = True;
  45. public unsigned char const *menu_string=0;
  46. public int menu_current=0;
  47. public int prompt_shift_size;
  48. /*}}}  */
  49.  
  50. /*{{{  history*/
  51. /*{{{  history type*/
  52. typedef struct History
  53.  { struct History *next;
  54.    histories id;
  55.    int size;
  56.    int used;
  57.    unsigned char **text;
  58.  } History;
  59. /*}}}  */
  60. /*{{{  variables*/
  61. private History history_data[]=
  62.  { { &(history_data[1]),search_history,0,0,0 },
  63.    { &(history_data[2]),replace_history,0,0,0 },
  64.    { &(history_data[3]),misc_history,0,0,0 },
  65.    { &(history_data[4]),file_history,0,0,0 },
  66.    { &(history_data[5]),error_history,0,0,0 },
  67.    { &(history_data[6]),arg_history,0,0,0 },
  68.    { &(history_data[7]),match_history,0,0,0 },
  69.    { &(history_data[8]),nomatch_history,0,0,0 },
  70.    { &(history_data[0]),shell_history,0,0,0 }
  71.  };
  72. private History *current_history= &(history_data[0]);
  73. public histories overwrite_history_id=default_history;
  74. /*}}}  */
  75.  
  76. /*{{{  switch_history        change current history, maybe create new one*/
  77. public boolean switch_history(histories h)
  78. { History *x;
  79.  
  80.   /*{{{  maybe overwrite called history*/
  81.   if (overwrite_history_id>default_history)
  82.      h=overwrite_history_id;
  83.   /*}}}  */
  84.   if (h==no_history)
  85.      return(False);
  86.   /*{{{  return existing history*/
  87.   for (x=current_history;;)
  88.      if (x->id==h)
  89.       { current_history=x;
  90.         return(True);
  91.       }
  92.      else if (x->next==current_history)
  93.         break;
  94.      else
  95.         x=x->next;
  96.   /*}}}  */
  97.   /*{{{  create new history*/
  98.   if (!(x=paket_malloc(sizeof(History))))
  99.      return(False);
  100.   x->id=h;
  101.   x->size=0;
  102.   x->used=0;
  103.   x->text=0;
  104.   x->next=current_history->next;
  105.   current_history->next=x;
  106.   current_history=x;
  107.   return(True);
  108.   /*}}}  */
  109. }
  110. /*}}}  */
  111. /*{{{  access_history        get correct index/text for a history*/
  112. public void access_history
  113.  ( int ind,
  114.    histories h,
  115.    boolean wrap_around,
  116.    int * const p_ind,
  117.    unsigned char ** const p_text
  118.  )
  119. {
  120.   if (switch_history(h))
  121.    /*{{{  set ind to value, inside of the used range*/
  122.      if (wrap_around)
  123.       { while (ind<START_HISTORY_INDEX) ind+=current_history->used+1;
  124.         while (ind>=current_history->used) ind-=current_history->used+1;
  125.       }
  126.      else
  127.       { if (ind<START_HISTORY_INDEX) ind=START_HISTORY_INDEX;
  128.         if (ind>=current_history->used) ind=current_history->used-1;
  129.       }
  130.    /*}}}  */
  131.   else
  132.    /*{{{  use empty start*/
  133.      ind=START_HISTORY_INDEX;
  134.    /*}}}  */
  135.   /*{{{  set return values*/
  136.   if (p_ind)
  137.      *p_ind=ind;
  138.   if (p_text)
  139.      *p_text=
  140.         (ind==START_HISTORY_INDEX)
  141.          ? (unsigned char*)empty_text
  142.          : current_history->text[ind];
  143.   /*}}}  */
  144. }
  145. /*}}}  */
  146. /*{{{  grow_history          changes size of the given historylist*/
  147. private void grow_history(histories h,int size)
  148. {
  149.   /*{{{  check arguments*/
  150.   if (!switch_history(h)) return;
  151.   if (size<=0 && current_history->size<=HISTORY_SIZE) return;
  152.   if (size<HISTORY_SIZE) size=HISTORY_SIZE;
  153.   if (size>HISTORY_MAX) size=HISTORY_MAX;
  154.   if (size==current_history->size) return;
  155.   /*}}}  */
  156.   /*{{{  maybe free history entries*/
  157.   { int i;
  158.  
  159.     if ((i=current_history->used-size)>0)
  160.      { unsigned char **s;
  161.  
  162.        s=current_history->text+size;
  163.        while (i>0)
  164.         { paket_free(*s);current_history->used--;s++;i--; }
  165.      }
  166.   }
  167.   /*}}}  */
  168.   /*{{{  try to change the list*/
  169.   { unsigned char **new_text;
  170.  
  171.     new_text=paket_malloc(size*sizeof(char*));
  172.     if (new_text)
  173.      { int new_used;
  174.        unsigned char **s;
  175.        unsigned char **d;
  176.        int i;
  177.  
  178.        new_used=0;
  179.        /*{{{  copy old to new*/
  180.        if ((i=current_history->used)>0)
  181.         { s=current_history->text;
  182.           d=new_text;
  183.           while (i-->0) { *d++= *s++;new_used++; }
  184.         }
  185.        /*}}}  */
  186.        /*{{{  update history struct*/
  187.        if (current_history->size)
  188.           paket_free(current_history->text);
  189.        current_history->text=new_text;
  190.        current_history->size=size;
  191.        current_history->used=new_used;
  192.        /*}}}  */
  193.      }
  194.   }
  195.   /*}}}  */
  196. }
  197. /*}}}  */
  198. /*{{{  shrink_history        reduce size of list to minimum*/
  199. public void shrink_history(void)
  200. { History *x,*y;
  201.  
  202.   x=y=current_history;
  203.   do grow_history(x->id,-1); while ((x=x->next)!=y);
  204. }
  205. /*}}}  */
  206. /*{{{  add_history           store text in a history list*/
  207. public void add_history(histories const h,unsigned char const * const text)
  208. {
  209.   if (!switch_history(h)) return;
  210.   /*{{{  maybe extend history*/
  211.   if (current_history->size==0 || current_history->size==current_history->used)
  212.      grow_history(h,HISTORY_SIZE+current_history->size);
  213.   /*}}}  */
  214.   if (current_history->size)
  215.    { unsigned char *tp;
  216.  
  217.      if ((tp=ori_malloc(ustrlen(text)+1)))
  218.       /*{{{  add the text*/
  219.       { int i;
  220.  
  221.         /*{{{  maybe remove oldest entry*/
  222.         if (current_history->size==current_history->used)
  223.          { current_history->used-=1;
  224.            paket_free(current_history->text[current_history->used]);
  225.          }
  226.         /*}}}  */
  227.         /*{{{  shift old entries*/
  228.         i=current_history->used;
  229.         while (i>0)
  230.          { current_history->text[i]=current_history->text[i-1];
  231.            i--;
  232.          }
  233.         /*}}}  */
  234.         ustrcpy((current_history->text[0]=tp),text);
  235.         current_history->used+=1;
  236.       }
  237.       /*}}}  */
  238.    }
  239. }
  240. /*}}}  */
  241. /*}}}  */
  242.  
  243. /*{{{  message               put a message under statusline*/
  244. public void message(unsigned char const * const s)
  245. {
  246.   enum dsp_size old_mode;
  247.  
  248.   ocl_msg((char*)s,0);
  249.   old_mode=dsp.norm;
  250.   dsp.norm=norm_dsp;
  251.   moveclreol(message_line,1);
  252.   move_cursor_to(message_line,1);
  253.   if (prt_bin_text(0,screen.w-(am?1:0),False,(unsigned char*)s))
  254.      status=True;
  255.   if (*s)
  256.      add_history(error_history,s);
  257.   oflush;
  258.   dsp.norm=old_mode;
  259. }
  260. /*}}}  */
  261. /*{{{  msg_message*/
  262. public void msg_message(msgtyp msg)
  263.  {
  264.    message(get_msg(msg));
  265.  }
  266. /*}}}  */
  267. /*{{{  verbose_msg_message*/
  268. public void verbose_msg_message(msgtyp msg)
  269.  { unsigned char const *s;
  270.  
  271.    s=get_msg(msg);
  272.    if (verbose)
  273.       message(s);
  274.  }
  275. /*}}}  */
  276. /*{{{  err_message           put a message under statusline with file and error*/
  277. public void err_message(msgtyp m,unsigned char const * const p)
  278. {
  279.   message(get_msg(m,p,strerror(errno)));
  280.   if (!scr_off)
  281.      sleep(1);
  282. }
  283. /*}}}  */
  284. /*{{{  warn_message          put a message and maybe switch on screen*/
  285. public void warn_message(unsigned char const * const s)
  286. {
  287.   int i;
  288.  
  289.   for (i=0;scr_off;ocl_screen_on(),i++);
  290.   if (verbose)
  291.    { bell_audible();
  292.      bell_visible();
  293.    }
  294.   message(s);
  295.   warn_delay();
  296.   for (;i;ocl_screen_off(),i--);
  297. }
  298. /*}}}  */
  299. /*{{{  no_message            remove message*/
  300. public void no_message(void)
  301. {
  302.   if (status)
  303.    { status = False;
  304.      moveclreol(message_line,1);
  305.    }
  306. }
  307. /*}}}  */
  308. /*{{{  readprompt            read a string with prompt, full editing*/
  309. public void readprompt
  310.  ( unsigned char * const Result,
  311.    unsigned char const * const prompt,
  312.    int const max,
  313.    histories const history,
  314.    unsigned char const * const start_pointer,
  315.    int start_offset
  316.  )
  317. {
  318.   /*{{{  variables*/
  319.   /*{{{  edit buffer*/
  320. #  define R_P_SIZE (2*LINELEN)
  321.   unsigned char txt_buff[R_P_SIZE];
  322.   unsigned char *txt;
  323.   unsigned char *gap_start;
  324.   unsigned char *gap_end;
  325.   int length;
  326.   /*}}}  */
  327.   /*{{{  dsp data*/
  328.   boolean dsp_full;
  329.   boolean new_shift;
  330.   int dsp_shift;
  331.   int c_pos;
  332.   /*}}}  */
  333.   TOKEN ch;
  334.   int hist_index=START_HISTORY_INDEX;
  335.   /*}}}  */
  336.  
  337.   status=True;
  338.   /*{{{  init the loop*/
  339.   /*{{{  txt_buffer*/
  340.   ustrcpy(txt_buff,prompt);
  341.   ustrcat(txt_buff,question);
  342.   for (txt=txt_buff;*txt;txt++);
  343.   /*}}}  */
  344.   /*{{{  edit data*/
  345.   *(gap_start=txt)='\0';
  346.   *(gap_end=txt_buff+R_P_SIZE-1)=0;
  347.   if (start_pointer)
  348.    { length=ustrlen(start_pointer);
  349.      gap_end-=length;
  350.      ustrcpy(gap_end,start_pointer);
  351.      while (start_offset-->=0 && (*gap_start= *gap_end))
  352.       { gap_end++;gap_start++; }
  353.      *gap_start='\0';
  354.    }
  355.   else
  356.      length=0;
  357.   /*}}}  */
  358.   /*{{{  dsp data*/
  359.   dsp_full=True;
  360.   new_shift=True;
  361.   /*}}}  */
  362.   /*}}}  */
  363.   do
  364.    /*{{{  edit loop*/
  365.    {
  366.      /*{{{  show line and cursor*/
  367.      if (dsp_full)
  368.       /*{{{  show whole prompt/string*/
  369.       { enum dsp_size old_mode;
  370.  
  371.         old_mode=dsp.norm;
  372.         dsp.norm=norm_dsp;
  373.         if (new_shift)
  374.          /*{{{  get new shift offset*/
  375.          { ocl_screen_off();
  376.            for (dsp_shift=0,c_pos=0;;)
  377.             { c_pos=prt_bin_text(0,screen.w,False,txt_buff+dsp_shift)+1;
  378.               if (c_pos>=screen.w && c_pos>1)
  379.                { int i=prompt_shift_size;
  380.  
  381.                  do
  382.                   { i--;
  383.                     dsp_shift++;
  384.                   }
  385.                  while (i && txt_buff[dsp_shift]);
  386.                }
  387.               else
  388.                  break;
  389.             }
  390.            ocl_screen_on();
  391.          }
  392.          /*}}}  */
  393.         /*{{{  clear line and set cursor*/
  394.         moveclreol(message_line,1);
  395.         move_cursor_to(message_line,1);
  396.         c_pos=prt_bin_text(0,screen.w,True,txt_buff+dsp_shift)+1;
  397.         /*}}}  */
  398.         if (*gap_end) prt_bin_text(c_pos-1,screen.w-c_pos,True,gap_end);
  399.         dsp_full=new_shift=False;
  400.         dsp.norm=old_mode;
  401.       }
  402.       /*}}}  */
  403.      move_cursor_to(message_line,c_pos);
  404.      /*}}}  */
  405.      ch=hide_key();
  406.      if (ch<O_NOP)
  407.       /*{{{  normal character*/
  408.       { length++;
  409.         *gap_start++=(unsigned char)ch;
  410.         *gap_start='\0';
  411.         switch (char_dsp_size((unsigned char)ch))
  412.          { case norm_dsp:
  413.            case ictrl_dsp:
  414.             /*{{{  print, if not at right margin*/
  415.               if (c_pos<screen.w-1)
  416.                /*{{{  prt the char, is single char and fits on line*/
  417.                { enum dsp_size old_mode;
  418.  
  419.                  old_mode=dsp.norm;
  420.                  dsp.norm=norm_dsp;
  421.                  prt_bin_text(c_pos,1,False,gap_start-1);
  422.                  c_pos++;
  423.                  if (*gap_end)
  424.                     prt_bin_text(c_pos-1,screen.w-c_pos,True,gap_end);
  425.                  dsp.norm=old_mode;
  426.                  break;
  427.                }
  428.                /*}}}  */
  429.             /*}}}  */
  430.            default:
  431.             /*{{{  mark dsp_full, maybe dsp_shift+*/
  432.             { new_shift=(c_pos>=screen.w);
  433.               dsp_full=True;
  434.             }
  435.             /*}}}  */
  436.          }
  437.         continue;
  438.       }
  439.       /*}}}  */
  440.      else
  441.       /*{{{  handle special commands*/
  442.         switch(ch)
  443.          {
  444.            /*{{{  O_DELETE*/
  445.            case O_DELETE:
  446.               if (gap_start!=txt)
  447.                { length--;
  448.                  deleted_ch= *--gap_start;
  449.                  *gap_start='\0';
  450.                  break;
  451.                }
  452.               continue;
  453.            /*}}}  */
  454.            /*{{{  O_LEFT*/
  455.            case O_LEFT:
  456.               if (gap_start!=txt)
  457.                { *--gap_end= *--gap_start;
  458.                  *gap_start='\0';
  459.                  break;
  460.                }
  461.               continue;
  462.            /*}}}  */
  463.            /*{{{  O_START_OF_LINE*/
  464.            case O_START_OF_LINE:
  465.               if (gap_start!=txt)
  466.                { do *--gap_end= *--gap_start; while (gap_start!=txt);
  467.                  *gap_start='\0';
  468.                  break;
  469.                }
  470.               continue;
  471.            /*}}}  */
  472.            /*{{{  O_RIGHT*/
  473.            case O_RIGHT:
  474.               if (*gap_end)
  475.                { *gap_start++= *gap_end++;
  476.                  *gap_start='\0';
  477.                  break;
  478.                }
  479.               continue;
  480.            /*}}}  */
  481.            /*{{{  O_FILEC*/
  482.            case O_FILE_C:
  483.               switch (*gap_end)
  484.                { case '\0':
  485.                  case ' ':
  486.                  case '\t':
  487.                   { char *f;
  488.  
  489.                     /*{{{  look for space or tab*/
  490.                     { char *x;
  491.  
  492.                       for (f=x=(char*)txt;*x && x<(char*)gap_start;)
  493.                          if (*x==' ' || *x=='\t')
  494.                             f= ++x;
  495.                          else
  496.                             x++;
  497.                     }
  498.                     /*}}}  */
  499.                     do_file_c(f);
  500.                   }
  501.                  default:
  502.                     continue;
  503.                }
  504.               break;
  505.            /*}}}  */
  506.            /*{{{  O_END_OF_LINE*/
  507.            case O_END_OF_LINE:
  508.             { unsigned char c;
  509.  
  510.               if ((c= *gap_end))
  511.                { do *gap_start++=c; while ((c= *++gap_end));
  512.                  *gap_start='\0';
  513.                  break;
  514.                }
  515.               continue;
  516.             }
  517.            /*}}}  */
  518.            /*{{{  M_END_OF_LINE*/
  519.            case M_END_OF_LINE:
  520.               macro_tag=(*gap_end=='\0');
  521.               continue;
  522.            /*}}}  */
  523.            /*{{{  M_BEGIN_OF_LINE*/
  524.            case M_BEGIN_OF_LINE:
  525.               macro_tag=(gap_start==txt);
  526.               continue;
  527.            /*}}}  */
  528.            /*{{{  O_UP,O_DOWN*/
  529.            case O_UP:
  530.            case O_DOWN:
  531.             { unsigned char *h_text;
  532.  
  533.               access_history
  534.                ( hist_index+((ch==O_UP)?HISTORY_ADD_OLD:HISTORY_ADD_NEW),
  535.                  history,True,&hist_index,&h_text
  536.                );
  537.               ustrcpy(txt,h_text);
  538.               txt[max-1]='\0';
  539.               length=ustrlen(txt);
  540.               gap_start=txt+length;
  541.               gap_end=txt_buff+R_P_SIZE-1;
  542.               break;
  543.             }
  544.            /*}}}  */
  545.            /*{{{  M_TEST_CHAR (LOW/HIGH/ ) _C*/
  546.            case M_TEST_CHAR_SET:
  547.            case M_TEST_CC:
  548.            case M_TEST_L_CC:
  549.            case M_TEST_H_CC:
  550.            case M_TEST_CHAR_LOW:
  551.            case M_TEST_CHAR_HIGH:
  552.            case M_TEST_CHAR:
  553.               do_cc_compare(*gap_end,ch);
  554.               continue;
  555.            /*}}}  */
  556.            /*{{{  M_TEST_STR*/
  557.            case M_TEST_STR:
  558.               do_str_compare(gap_end);
  559.               continue;
  560.            /*}}}  */
  561.            /*{{{  M_STORE_C*/
  562.            case M_STORE_C:
  563.              ocl_var[get_arg("store-char-var")].v= *gap_end;
  564.              continue;
  565.            /*}}}  */
  566.            /*{{{  O_TOGGLE_CASE*/
  567.            case O_TOGGLE_CASE:
  568.             { unsigned char c;
  569.  
  570.               if ((c = *gap_end) && isalpha(c))
  571.                  *gap_end=isupper(c)?tolower(c):toupper(c);
  572.               break;
  573.             }
  574.            /*}}}  */
  575.            default:
  576.               continue;
  577.          }
  578.       /*}}}  */
  579.      dsp_full=new_shift=True;
  580.    }
  581.    /*}}}  */
  582.   while (length<max && ch!=O_RETURN && !aborted);
  583.   if (aborted)
  584.      *Result='\0';
  585.   else
  586.    /*{{{  return string and store in history*/
  587.    { ustrcpy(Result,txt);
  588.      ustrcat(Result,gap_end);
  589.      if (*Result || history==replace_history)
  590.         add_history(history,Result);
  591.    }
  592.    /*}}}  */
  593. }
  594. /*}}}  */
  595. /*{{{  yes                   ask for boolean*/
  596. public boolean yes(unsigned char const * const q)
  597. {
  598. # define YES_LG 8
  599.   unsigned char temp[YES_LG+1];
  600.  
  601.   do
  602.    { s_readprompt(temp,q,YES_LG,no_history);
  603.      temp[0]=toupper(temp[0]);
  604.      if (temp[0]==YES)
  605.         return(True);
  606.      else if (temp[0]==NO)
  607.         break;
  608.    }
  609.   while (!aborted);
  610.  
  611.   return(False);
  612. }
  613. /*}}}  */
  614. /*{{{  menu_item             display a menu string and get item number*/
  615. public int menu_item
  616.  ( unsigned char const * prompt,
  617.    int start,
  618.    boolean const direct,
  619.    boolean const move_current
  620.  )
  621. { while (*prompt==' ') prompt++;
  622.   ori_assert(bd.scr.cur_shift_w<=LINELEN*max_dsp,"shift-check");
  623.   title_op(UPDTITLE);
  624.   status=True;
  625.   for (;;)
  626.    /*{{{  display and get input*/
  627.    {
  628.      /*{{{  variables*/
  629.      int i;
  630.      int max;
  631.      int m_shift;
  632.      TOKEN cmd;
  633.      unsigned char *s;
  634.      /*}}}  */
  635.  
  636.      /*{{{  print menu and get code*/
  637.      /*{{{  check, if start to low*/
  638.      if (start<0) start=0;
  639.      /*}}}  */
  640.      /*{{{  print menu line*/
  641.      { int lg;
  642.  
  643.        for (m_shift=0;;m_shift++)
  644.         { unsigned char c;
  645.  
  646.           moveclreol(message_line,1);
  647.           move_cursor_to(message_line,1);
  648.           s=(unsigned char*)prompt;
  649.           /*{{{  skip leading entries, if to long*/
  650.           if (m_shift)
  651.            { i=m_shift;
  652.              for (;i;i--)
  653.               { while (*s && *s!=' ')
  654.                    s++;
  655.                 while (*s==' ')
  656.                    s++;
  657.               }
  658.            }
  659.           /*}}}  */
  660.           menu_string=s;
  661.           if (m_shift && soln_str)
  662.            { oputc(soln_str);
  663.              menu_string--;
  664.            }
  665.           i=0;
  666.           lg=screen.w-5;
  667.           while ((c= *s++))
  668.              if (c==' ')
  669.               /*{{{  print spaces*/
  670.               { if (lg)
  671.                  { oputc(' ');
  672.                    lg--;
  673.                  }
  674.               }
  675.               /*}}}  */
  676.              else
  677.               /*{{{  print mark*/
  678.               { boolean cur;
  679.  
  680.                 cur=(i==start-m_shift) && lg;
  681.                 /*{{{  maybe mark current*/
  682.                 if (cur)
  683.                    if (move_current && so && !sg)
  684.                       do_standout();
  685.                 /*}}}  */
  686.                 /*{{{  print leading space decode*/
  687.                 if (c==(unsigned char)SPACE_CHAR)
  688.                  { unsigned char *sp=(unsigned char*)SPACE;
  689.  
  690.                    while (lg && *sp)
  691.                     { oputc(*sp);
  692.                       sp++;
  693.                       lg--;
  694.                     }
  695.                    c= *s++;
  696.                  }
  697.                 /*}}}  */
  698.                 /*{{{  print body of tag*/
  699.                 while (c!='\0' && c!=' ')
  700.                  { if (lg)
  701.                     { oputc(c);
  702.                       lg--;
  703.                     }
  704.                    c= *s++;
  705.                  }
  706.                 /*}}}  */
  707.                 /*{{{  maybe end mark current*/
  708.                 if (move_current)
  709.                    if (so && !sg)
  710.                       do_standend();
  711.                    else if (lg)
  712.                     { oputc(CURR_MARK[0]);
  713.                       lg--;
  714.                     }
  715.                 /*}}}  */
  716.                 s-=1;
  717.                 i++;
  718.               }
  719.               /*}}}  */
  720.           if (lg==0)
  721.              oputc(eoln_str);
  722.           oputs((unsigned char*)question);
  723.           if (m_shift==0)
  724.              max=i;
  725.           if (lg || (start==m_shift) || !move_current)
  726.              break;
  727.         }
  728.      }
  729.      /*}}}  */
  730.      /*{{{  check, if start to high*/
  731.      if (start>=max)
  732.       { start=max-1;
  733.         continue;
  734.       }
  735.      /*}}}  */
  736.      i=start;
  737.      /*{{{  set current adress for mouse handling*/
  738.      if (move_current && !(so && !sg))
  739.         menu_current=start-m_shift;
  740.      else
  741.         menu_current= -1;
  742.      /*}}}  */
  743.      if (direct)
  744.       /*{{{  read the key direct from keyboard*/
  745.       { disable_abort();
  746.         enable_echo(False);
  747.         /* if aborted is true before get_key is called, then ... :-( */
  748.         cmd=get_key();
  749.         enable_echo(True);
  750.         enable_abort();
  751.       }
  752.       /*}}}  */
  753.      else
  754.       /*{{{  hide_key*/
  755.         cmd=hide_key();
  756.       /*}}}  */
  757.      menu_string=0;
  758.      /*}}}  */
  759.      /*{{{  abort returns -1*/
  760.      if (aborted)
  761.       { start= -1;
  762.         break;
  763.       }
  764.      /*}}}  */
  765.      /*{{{  maybe handle left/right*/
  766.      if (move_current)
  767.         if (cmd==O_LEFT)
  768.          { start=--i;
  769.            continue;
  770.          }
  771.         else if (cmd==O_RIGHT)
  772.          { if (i<max-1)
  773.               start=++i;
  774.            continue;
  775.          }
  776.      /*}}}  */
  777.      if (cmd<O_NOP)
  778.       /*{{{  look in list for corresponding entry*/
  779.       { unsigned char ch;
  780.  
  781.         for(ch=toupper((unsigned char)cmd),s=(unsigned char*)prompt,i=0;*s;)
  782.          /*{{{  handle items*/
  783.          { if (*s==' ')
  784.             /*{{{  skip gap*/
  785.               while (*(++s)==' ');
  786.             /*}}}  */
  787.            else if (*s==(unsigned char)SPACE_CHAR && ch==' ')
  788.             /*{{{  hit correct space -> ret*/
  789.               return(i);
  790.             /*}}}  */
  791.            else if (ch==toupper(*s))
  792.             /*{{{  hit correct non-space -> ret*/
  793.               return(i);
  794.             /*}}}  */
  795.            else
  796.             /*{{{  skip item*/
  797.             { while (*(++s) && *s!=' ');
  798.               i++;
  799.             }
  800.             /*}}}  */
  801.            continue;
  802.          }
  803.          /*}}}  */
  804.         continue;
  805.       }
  806.       /*}}}  */
  807.      else if (cmd==O_RETURN)
  808.         break;
  809.    }
  810.    /*}}}  */
  811.   return(start);
  812. }
  813. /*}}}  */
  814. /*{{{  show_string           display string (with \n) on screen*/
  815. public boolean show_string(unsigned char const *s,boolean const clr)
  816. {
  817.   if (s && *s)
  818.    /*{{{  display it, using the whole screen*/
  819.    { int x,y;
  820.      unsigned char c;
  821.      enum dsp_size old_mode;
  822.  
  823.      old_mode=dsp.norm;
  824.      dsp.norm=norm_dsp;
  825.      for (y=0,x=INT_MAX;;)
  826.       /*{{{  show whole string*/
  827.       {
  828.         /*{{{  maybe line break*/
  829.         if (x>screen.w)
  830.            if (++y==screen.h)
  831.               break;
  832.            else
  833.               move_cursor_to(y,x=1);
  834.         /*}}}  */
  835.         switch ((c=(s?*s++:' ')))
  836.          {
  837.            /*{{{  \n -> line break*/
  838.            case '\n':
  839.               moveclreol(y,x);
  840.               x=INT_MAX;
  841.               continue;
  842.            /*}}}  */
  843.            /*{{{  print*/
  844.            case '\0':
  845.               if (!clr || y>screen.h)
  846.                  break;
  847.               s=0;
  848.            case '\t':
  849.               c=' ';
  850.            default:
  851.               oputc(c);
  852.               x++;
  853.               continue;
  854.            /*}}}  */
  855.          }
  856.         break;
  857.       }
  858.       /*}}}  */
  859.      oflush;
  860.      dsp.norm=old_mode;
  861.      return(True);
  862.    }
  863.    /*}}}  */
  864.   return(False);
  865. }
  866. /*}}}  */
  867. /*{{{  help                  display help or binding*/
  868. /*{{{  mark strings for rc-help*/
  869. static char alias[REF_TAG_LG+1];
  870. static char numb[REF_TAG_LG+1];
  871. static char ab[REF_TAG_LG+1];
  872. #ifdef MOUSY
  873.    static char mouse[REF_TAG_LG+1];
  874. #endif
  875. static char const * const mark_field[]=
  876. { alias,
  877.   numb,
  878.   ab,
  879. #ifdef MOUSY
  880.   mouse,
  881. #endif
  882.   0
  883. };
  884. #define marks (mark_field+1)
  885. #ifdef MOUSY
  886. #  define end_marks (mark_field+4)
  887. #else
  888. #  define end_marks (mark_field+3)
  889. #endif
  890. /*}}}  */
  891. /*{{{  buffer for line wrap*/
  892. private char help_cut_buff[RC_HELP_LEN+1];
  893. /*}}}  */
  894. /*{{{  get_help_line*/
  895. private char *get_help_line
  896.  ( char * const buff,
  897.    FILE * const f,
  898.    const boolean tag_test,
  899.    const unsigned char *pattern,
  900.    const unsigned char *skip,
  901.    int * const skipped
  902.  )
  903.  {
  904.    /*{{{  get line*/
  905.    if (help_cut_buff[0])
  906.     /*{{{  use tail of last line*/
  907.       strcpy(buff,help_cut_buff);
  908.     /*}}}  */
  909.    else
  910.     /*{{{  get new line*/
  911.     { char const * const *tags;
  912.  
  913.       for (tags=(char const*const*)(tag_test?marks:0);;)
  914.        { char const * const *cmp_tag_list;
  915.          char *b;
  916.  
  917.          if (!fgets((b=help_cut_buff),RC_HELP_LEN,f))
  918.           /*{{{  nothing found, return 0*/
  919.           { help_cut_buff[0]='\0';
  920.             return(0);
  921.           }
  922.           /*}}}  */
  923.          if ((cmp_tag_list=tags))
  924.           /*{{{  next one, if tags do not match this line*/
  925.           { while (*cmp_tag_list)
  926.              { const char *cur_cmp_tag= *(cmp_tag_list++);
  927.  
  928.                if (*cur_cmp_tag)
  929.                 /*{{{  compare line and not empty tag*/
  930.                 { char *d=b;
  931. #                 ifdef MOUSY
  932.                      boolean change=(cur_cmp_tag==mouse);
  933. #                 endif
  934.  
  935.                   while (*cur_cmp_tag && *cur_cmp_tag==*d)
  936.                    { cur_cmp_tag++;
  937.                      d++;
  938.                    }
  939.                   if (*cur_cmp_tag=='\0')
  940.                      if (*d==REF_NODE_LIMITER)
  941.                       /*{{{  prepare string for return*/
  942.                       { b=d+1;
  943.                         ref_uncompress_text(b,buff);
  944. #                       ifdef MOUSY
  945.                            if (change)
  946.                             /*{{{  decode the mouse buttonnumber to a name*/
  947.                             { char *m_s;
  948.  
  949.                               /*{{{  move to end of string*/
  950.                               for (m_s=buff;*m_s>=' ';m_s++);
  951.                               /*}}}  */
  952.                               /*{{{  decode mouse button*/
  953.                               { unsigned int c;
  954.  
  955.                                 c=*--m_s-REF_COUNT_BASE;
  956.                                 strcpy
  957.                                  ( m_s,
  958.                                    (mouse_b_count[use_mouse]>c)
  959.                                      ? mouse_b_names[use_mouse][c]
  960.                                      : (char*)i_to_ua(c)
  961.                                  );
  962.                               }
  963.                               /*}}}  */
  964.                             }
  965.                             /*}}}  */
  966. #                       endif
  967.                         b=buff;
  968.                         cmp_tag_list--;
  969.                         break;
  970.                       }
  971.                       /*}}}  */
  972.                      else if (*d==REF_NODE_ALIAS)
  973.                       /*{{{  use alias field too and set to pointed value*/
  974.                       { unsigned char *s;
  975.  
  976.                         /*{{{  cp alias to alias-part in marks (without \r \n)*/
  977.                         for
  978.                          ( s=(unsigned char*)d+1,
  979.                            d=alias
  980.                          ; (*((unsigned char*)d++)= *s++)>=REF_NODE_LIMITER
  981.                          ;
  982.                          );
  983.                         d[-1]='\0';
  984.                         /*}}}  */
  985.                         tags=(char const*const*)mark_field;
  986.                         cmp_tag_list=end_marks;
  987.                       }
  988.                       /*}}}  */
  989.                 }
  990.                 /*}}}  */
  991.              }
  992.             if (!*cmp_tag_list)
  993.                continue;
  994.           }
  995.           /*}}}  */
  996.          if (pattern && !ustrstr((unsigned char*)b,pattern))
  997.             goto next_try;
  998.          if (skip && !ustrstr((unsigned char*)b,skip))
  999.           { if (skipped)
  1000.                (*skipped)++;
  1001.          next_try:
  1002.             if (tags==(char const*const*)mark_field)
  1003.                tags++;
  1004.             continue;
  1005.           }
  1006.          if (!cmp_tag_list)
  1007.             strcpy(buff,help_cut_buff);
  1008.          break;
  1009.        }
  1010.       /*{{{  cut at newline/cr*/
  1011.       { char *d;
  1012.  
  1013.         for (d=buff;;d++)
  1014.          { switch (*d)
  1015.             { case '\r':
  1016.               case '\n':
  1017.                  *d='\0';
  1018.               case '\0':
  1019.                  break;
  1020.               default:
  1021.                  continue;
  1022.             }
  1023.            break;
  1024.          }
  1025.       }
  1026.       /*}}}  */
  1027.     }
  1028.     /*}}}  */
  1029.    /*}}}  */
  1030.    /*{{{  maybe store tail of long line/splitted line part*/
  1031.    if (strlen(buff)>(bd.scr.txt_size.w-1))
  1032.     { strcpy(help_cut_buff,buff+(bd.scr.txt_size.w-1));
  1033.       buff[bd.scr.txt_size.w-1]='\0';
  1034.     }
  1035.    else
  1036.       help_cut_buff[0]='\0';
  1037.    /*}}}  */
  1038.  
  1039.    return(buff);
  1040.  }
  1041. /*}}}  */
  1042. /*{{{  help_seek*/
  1043. #define help_seek(f,o) (help_cut_buff[0]='\0',fseek((f),(o),SEEK_SET))
  1044. /*}}}  */
  1045.  
  1046. public void help(boolean show_help)
  1047. {
  1048.   /*{{{  local variables*/
  1049.   FILE *fp;
  1050.   boolean help_as_rc=False;
  1051.   boolean displayed=False;
  1052.   boolean complain=True;
  1053.   off_t offset;
  1054.   unsigned char pat_buff[LINELEN+1];
  1055.   const unsigned char *pattern=0;
  1056.   unsigned char skip_buff[LINELEN+1];
  1057.   const unsigned char *skip=0;
  1058.   int shown_lines=0;
  1059.   boolean killing=False;
  1060.   unsigned char help_prompt[MSG_LENGTH+1];
  1061.   /*}}}  */
  1062.  
  1063.   /*{{{  get the prompt*/
  1064.   ustrcpy(help_prompt,get_msg(M_ANY_Q));
  1065.   last_message=M_BASE_FORMAT;
  1066.   /*}}}  */
  1067.   /*{{{  open the file*/
  1068.   if (show_help)
  1069.    { char *sysfile;
  1070.  
  1071.      if (ocl_var[var_mod_beh].v<0)
  1072.         ocl_var[var_mod_beh].v=0;
  1073.      sysfile=ocl_var[var_mod_beh].v?0:open_sysfile(M_HELPSTR,(char*)0);
  1074.      if (!sysfile ||  !*sysfile || !(fp=fopen(sysfile,(char*)"rb")))
  1075.       { int err_no;
  1076.  
  1077.         err_no=errno;
  1078.         fp=rcfile
  1079.             ? rcfile
  1080.             : (rcfile=fopen(open_sysfile(M_RCSTR,(char*)0),(char*)"rb"));
  1081.         errno=err_no;
  1082.         help_as_rc=True;
  1083.       }
  1084.    }
  1085.   else
  1086.      fp=fopen(open_sysfile(M_RCSTR,(char*)0),(char*)"rb");
  1087.   /*}}}  */
  1088.   /*{{{  set filter marks*/
  1089.   if (!show_help)
  1090.    /*{{{  set leading marks for bindinglist*/
  1091.    { ref_code_tag(numb,bind_mark[0]);
  1092.      ref_code_tag(ab,abort_kbd);
  1093. #    ifdef MOUSY
  1094.         if (use_mouse==no_mouse)
  1095.            mouse[0]='\0';
  1096.         else
  1097.            ref_code_tag(mouse,mouse_kbd);
  1098. #    endif
  1099.      offset=helpofs;
  1100.    }
  1101.    /*}}}  */
  1102.   else
  1103.    /*{{{  clear or set marks for help*/
  1104.      if (help_as_rc)
  1105.       { show_help=False;
  1106. #   ifdef MOUSY
  1107.         mouse[0]=
  1108. #   endif
  1109.         ab[0]='\0';
  1110.         /*{{{  get correct seek offset*/
  1111.         { static off_t ref_class_ofs=0;
  1112.           static off_t ref_file_ofs=0;
  1113.           off_t x;
  1114.           int id;
  1115.  
  1116.           /*{{{  get limiter help id, maybe set no-complain, set offset*/
  1117.           if (ocl_var[var_mod_beh].v)
  1118.            { id=ref_class_id;
  1119.              complain=False;
  1120.              x=ref_class_ofs;
  1121.              offset=ref_file_ofs?ref_file_ofs:helpofs;
  1122.            }
  1123.           else
  1124.            { id=ref_file_id;
  1125.              x=ref_file_ofs;
  1126.              offset=helpofs;
  1127.            }
  1128.           /*}}}  */
  1129.           if (!x)
  1130.            /*{{{  try to get seek offset, using kbd-0 tag field*/
  1131.            { if (-1!=help_seek(fp,(off_t)offset))
  1132.               { char line[RC_HELP_LEN+1];
  1133.  
  1134.                 ref_code_tag(numb,ref_kbd-id);
  1135.                 if
  1136.                  (    !get_help_line(line,fp,True,pattern,(const unsigned char *)0,(int*)0)
  1137.                    || !(x=ftell(fp))
  1138.                  )
  1139.                    x=helpofs;
  1140.                 if (complain)
  1141.                    ref_file_ofs=x;
  1142.                 else
  1143.                    ref_class_ofs=x;
  1144.               }
  1145.            }
  1146.            /*}}}  */
  1147.           offset=x;
  1148.         }
  1149.         /*}}}  */
  1150.         ref_code_tag(numb,ref_kbd-ocl_var[var_mod_beh].v);
  1151.       }
  1152.      else
  1153.         offset=ftell(fp);
  1154.    /*}}}  */
  1155.   /*}}}  */
  1156.   /*{{{  init compression data*/
  1157.   if (!show_help && !(fseek(fp,compofs,SEEK_SET)))
  1158.      ref_read_comp_data(fp);
  1159.   /*}}}  */
  1160.   /*{{{  show-loop*/
  1161.   foo:
  1162.   if (fp)
  1163.    {
  1164.      /*{{{  variables*/
  1165.      char line[RC_HELP_LEN+1];
  1166.      int li;
  1167.      int cmd;
  1168.      /*}}}  */
  1169.  
  1170.      if (-1!=help_seek(fp,(off_t)offset))
  1171.       { if (killing)
  1172.          /*{{{  kill whole view*/
  1173.          { warn_message(get_msg(M_KILLING));
  1174.            bd.scr.txt_size.w+=RC_HELP_LEN;
  1175.            for
  1176.             (
  1177.             ; get_help_line(line,fp,!show_help,pattern,(const unsigned char*)0,(int*)0)
  1178.             ;
  1179.             )
  1180.             { element *p;
  1181.  
  1182.               p=proc_new_element();
  1183.               set_data(p,(unsigned char const *)line,True);
  1184.               append_to_pick(p);
  1185.             }
  1186.            bd.scr.txt_size.w-=RC_HELP_LEN;
  1187.            killing=False;
  1188.            goto foo;
  1189.          }
  1190.          /*}}}  */
  1191.         /*{{{  overread leading text*/
  1192.         for
  1193.         (
  1194.           li=shown_lines;
  1195.           li && get_help_line(line,fp,!show_help,pattern,(const unsigned char *)0,(int*)0);
  1196.           li--
  1197.         );
  1198.         /*}}}  */
  1199.         for (;!aborted;)
  1200.          /*{{{  show screen and prompt*/
  1201.          { li=0;
  1202.            /*{{{  show one screen*/
  1203.            { enum dsp_size old_mode;
  1204.  
  1205.              old_mode=dsp.norm;
  1206.              dsp.norm=norm_dsp;
  1207.              /*{{{  show lines*/
  1208.              { char *s;
  1209.  
  1210.                while
  1211.                 (    (li<bd.scr.txt_size.h)
  1212.                   && (s=get_help_line
  1213.                          ( line,
  1214.                            fp,
  1215.                            !show_help,
  1216.                            pattern,
  1217.                            skip,skip?&shown_lines:(int*)0)
  1218.                          )
  1219.                 )
  1220.                 { skip=0;
  1221.                   displayed=True;
  1222.                   shown_lines++;
  1223.                   li++;
  1224.                   move_prt_clreol(li,1,0,bd.scr.txt_size.w-1,True,(unsigned char*)s);
  1225.                   oflush;
  1226.                 }
  1227.              }
  1228.              /*}}}  */
  1229.              /*{{{  maybe clear to end of screen*/
  1230.              { int x;
  1231.  
  1232.                if ((x=li)) while (x<bd.scr.txt_size.h) moveclreol(++x,1);
  1233.              }
  1234.              /*}}}  */
  1235.              dsp.norm=old_mode;
  1236.            }
  1237.            /*}}}  */
  1238.            if (li)
  1239.             /*{{{  prompt for key*/
  1240.             { ori_assert(bd.scr.cur_shift_w<=LINELEN*max_dsp,"shift-check");
  1241.               title_op(PRTTITLE);
  1242.               last_message=M_ANY_Q;
  1243.               cmd=1;
  1244.               cmd=menu_item(help_prompt,cmd,False,False);
  1245.               switch (cmd)
  1246.                {
  1247.                  case 0:
  1248.                   /*{{{  next page*/
  1249.                     break;
  1250.                   /*}}}  */
  1251.                  case 1:
  1252.                   /*{{{  next line*/
  1253.                     shown_lines-=bd.scr.txt_size.h;
  1254.                     shown_lines++;
  1255.                     if (shown_lines<0) shown_lines=0;
  1256.                     goto foo;
  1257.                   /*}}}  */
  1258.                  case 2:
  1259.                   /*{{{  page up*/
  1260.                     shown_lines-=(bd.scr.txt_size.h)<<1;
  1261.                     if (shown_lines<0) shown_lines=0;
  1262.                     goto foo;
  1263.                   /*}}}  */
  1264.                  case 3:
  1265.                   /*{{{  quit*/
  1266.                     goto bar;
  1267.                   /*}}}  */
  1268.                  case 4:
  1269.                   /*{{{  prompt for the filter*/
  1270.                     s_readprompt(pat_buff,(unsigned char*)"filter",LINELEN,misc_history);
  1271.                     if (aborted)
  1272.                        goto bar;
  1273.                     pattern=pat_buff[0]?(const unsigned char*)pat_buff:0;
  1274.                     shown_lines=0;
  1275.                     goto foo;
  1276.                   /*}}}  */
  1277.                  case 5:
  1278.                   /*{{{  prompt for search pattern*/
  1279.                     s_readprompt(skip_buff,get_msg(M_SEARCH),LINELEN,misc_history);
  1280.                     if (aborted)
  1281.                        goto bar;
  1282.                     shown_lines-=(bd.scr.txt_size.h-1);
  1283.                     if (shown_lines<0)
  1284.                        shown_lines=1;
  1285.                     skip=skip_buff[0]?(const unsigned char*)skip_buff:0;
  1286.                     goto foo;
  1287.                   /*}}}  */
  1288.                  case 6:
  1289.                   /*{{{  kill all text*/
  1290.                     killing=True;
  1291.                     shown_lines-=bd.scr.txt_size.h;
  1292.                     goto foo;
  1293.                   /*}}}  */
  1294.                }
  1295.  
  1296.             }
  1297.             /*}}}  */
  1298.            else
  1299.               goto bar;
  1300.          }
  1301.          /*}}}  */
  1302.       }
  1303.      bar:
  1304.      /*{{{  check closing the helpfile*/
  1305.      if (fp!=rcfile && fclose(fp)<0)
  1306.         err_message(M_CLOSE_FAILED,empty_text);
  1307.      /*}}}  */
  1308.    }
  1309.   no_message();
  1310.   /*{{{  maybe there was no ref in the rc-file, so complain then*/
  1311.   if (!displayed && complain)
  1312.    { show_string(get_copyright(True),True);
  1313.      move_cursor_to(screen.h,1);
  1314.      hide_key();
  1315.    }
  1316.   /*}}}  */
  1317.   /*}}}  */
  1318.   /*{{{  free internal data*/
  1319.   ref_free_comp_data();
  1320.   /*}}}  */
  1321. }
  1322. /*}}}  */
  1323.